using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Library.WebControls.Ds;

namespace Library.WebControls.SimpleTreeView {
	[ToolboxBitmap(typeof(SpTreeView), "Library.WebControls.SimpleTreeView.SpTreeView.bmp")]
	[Designer(typeof(SpTreeViewDesign))]
	[SupportsEventValidation]
	[DesignTimeVisible(true)]
	[ToolboxData("<{0}:SpTreeView runat=server></{0}:SpTreeView>")]
	public class SpTreeView : BaseAjaxControl, IEffectControl {
		protected const string SpTreeViewCallbackParameter = "__SPTREEVIEWRQP_";
		protected const string SpTreeViewCallbackFunction = "__SPTREEVIEWF_";
		protected const string SpTreeViewCallbackParrentKey = "__SPTREEVIEWPK_";
		protected const string SpTreeViewCallbackParrentLevel = "__SPTREEVIEWPL_";
		protected const string SpTreeViewCallbackServerId = "__SPTREEVIEWSID_";
		protected static Type TreeViewType = typeof(SpTreeView);

		public SpTreeView() {
			ClientScript = new ClientScript();
		}
		private bool _isCallback;
		private RequestType _requestType = RequestType.None;
		private HtmlGenericControl _ul;
		[Browsable(false)]
		public RequestType RequestType {
			get { return _requestType; }
		}
		[PersistenceMode(PersistenceMode.InnerProperty)]
		[MergableProperty(false)]
		[Category("Data")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[DefaultValue("")]
		public ClientScript ClientScript {
			private set;
			get;
		}
		protected override string StyleSheetFileName {
			get { return "sptreeview-ui.css"; }
		}

		[DefaultValue(""), PersistenceMode((PersistenceMode.InnerProperty)), Browsable(false),
		 TemplateContainer(typeof(SpTreeNodeItemTemplate))]
		public ITemplate ItemTemplate { get; set; }
		[Browsable(false)]
		public object DataSource { get; set; }

		public string TextField { get; set; }

		public string KeyField { get; set; }

		public bool AlwaysCallbackInExpend { get; set; }

		public Unit Width {
			get {
				EnsureChildControls();
				return new Unit(_ul.Style[HtmlTextWriterStyle.Width]);
			}
			set {
				EnsureChildControls();
				_ul.Style[HtmlTextWriterStyle.Width] = value.ToString();
			}
		}

		public override bool IsCallback {
			get { return _isCallback; }
		}

		public override string ID {
			get {
				EnsureChildControls();
				return _ul.ID;
			}
			set {
				EnsureChildControls();
				_ul.ID = value;
			}
		}

		public override string ClientID {
			get {
				EnsureChildControls();
				return _ul.ClientID;
			}
		}

		#region IEffectControl Members

		public Effect DisplayEffect { get; set; }

		public int TimeEffect { get; set; }

		public int StepEffect { get; set; }

		#endregion

		public static bool IsSpTreeViewCallback(Page page) {
			try {
				return !String.IsNullOrEmpty(page.Request[SpTreeViewCallbackServerId]);
			} catch {
				return false;
			}
		}

		public event EventHandler<SpTreeNodeExpendedEventArgs> NodeExpended;
		public event SimpleItemBoundEventHandler<SpTreeNodeItemTemplate> ItemBound;
		public event CustomCallbackEventHandler CustomCallback;
		public event CustomCallbackEventHandler DataCallback;

		protected string RequestParameter = String.Empty;
		protected string ExpendedKey = String.Empty;
		protected int ExpendedLevel;
		protected override void OnInit(EventArgs e) {
			base.OnInit(e);
			_isCallback = IsSpTreeViewCallback(Page) &&
										String.Compare(ClientID, Page.Request[SpTreeViewCallbackServerId], true) == 0;
			if (_isCallback) {
				ParseRequestInfo();
			}
		}

		protected void ParseRequestInfo() {
			if (Request == null) return;
			int? requestType = Page.Request[SpTreeViewCallbackFunction].ParseInt();
			if (requestType.HasValue) {
				_requestType = (RequestType)requestType.Value;
			}

			RequestParameter = Request[SpTreeViewCallbackParameter];
			ExpendedKey = Request[SpTreeViewCallbackParrentKey];
			var level = Request[SpTreeViewCallbackParrentLevel].ParseInt();
			if (level.HasValue) ExpendedLevel = level.Value;
			else ExpendedLevel = 0;
		}

		protected override void OnLoad(EventArgs e) {
			base.OnLoad(e);
			IncludeScriptOnLoad(TreeViewType, "TreeView", "Library.WebControls.SimpleTreeView.include.SpTreeView.js", EffectLib);
			if (IsCallback) {
				switch (RequestType) {
					case RequestType.Expended:
						OnNodeExpended(new SpTreeNodeExpendedEventArgs(ExpendedKey, RequestParameter, ExpendedLevel));
						break;
					case RequestType.DataCallback:
						OnDataCallback(new CustomCallbackEventArgs(RequestParameter));
						break;
					case RequestType.CustomCallback:
						OnCustomCallback(new CustomCallbackEventArgs(RequestParameter));
						break;
				}
			}
		}

		protected virtual void OnItemBound(SimpleItemBoundEventArgs<SpTreeNodeItemTemplate> e) {
			SimpleItemBoundEventHandler<SpTreeNodeItemTemplate> handler = ItemBound;
			if (handler != null) {
				handler(this, e);
			}
		}

		protected virtual void OnNodeExpended(SpTreeNodeExpendedEventArgs e) {
			var handler = NodeExpended;
			if (handler != null) {
				try {
					handler(this, e);
					ProcessCustomCallbackEventArgs(e);
				} catch (Exception ex) {
					WriteError(ex);
				}
			}
		}

		protected virtual void OnCustomCallback(CustomCallbackEventArgs e) {
			CustomCallbackEventHandler handler = CustomCallback;
			if (handler != null) {
				try {
					handler(this, e);
					ProcessCustomCallbackEventArgs(e);
				} catch (Exception ex) {
					WriteError(ex);
				}
			}
		}

		protected virtual void OnDataCallback(CustomCallbackEventArgs e) {
			CustomCallbackEventHandler handler = DataCallback;
			if (handler != null) {
				try {
					handler(this, e);
					ProcessCustomCallbackEventArgs(e);
				} catch (Exception ex) {
					WriteError(ex);
				}
			}
		}


		protected override void CreateChildControls() {
			_ul = new TreeViewRootNode();
			Controls.Add(_ul);
		}

		public override void DataBind() {
			//EnsureChildControls();
			_ul.Controls.Clear();
			if (DataSource == null) {
				return;
			}
			var treeViewSource = DataSource as ITreeViewDataSource;
			if (treeViewSource != null) {
				BindingTreeViewDataSource(treeViewSource);
			} else {
				var dsWrapper = new DataSourceWrapper(DataSource);
				while (dsWrapper.MoveNext()) {
					object key = dsWrapper.Current.GetPropertyValue(KeyField);
					var li = new TreeViewItemNode(key, ExpendedLevel + 1);
					_ul.Controls.Add(li);

					li.TreeViewTitle.CreateCollapse(ClientName);
					var spText = li.TreeViewTitle.SpanContent;
					spText.DataItem = dsWrapper.Current.OriginalItem;
					spText.DataItemIndex = dsWrapper.Index;
					spText.DisplayIndex = dsWrapper.Index;
					if (ItemTemplate == null) {
						if (!String.IsNullOrEmpty(TextField))
							spText.InnerText = String.Format("{0}", dsWrapper.Current.GetPropertyValue(TextField));
					} else {
						ItemTemplate.InstantiateIn(spText);
					}

					var itemBoundEventArgs = new SimpleItemBoundEventArgs<SpTreeNodeItemTemplate>(dsWrapper.Current,spText);
					OnItemBound(itemBoundEventArgs);
				}
			}
			base.DataBind();
		}

		private void BindingTreeViewDataSource(IEnumerable<ITreeViewDataItem> source) {
			long unique = 0;
			int index = -1;
			foreach (var item in source) {
				index++;
				_ul.Controls.Add(CreateLiNode(item, index, 0, ref unique));
			}
			//for (int i = 0; i < source.Count; i++) {
			//  _ul.Controls.Add(CreateLiNode(source[i], i, 0, ref unique));
			//}
		}

		private HtmlGenericControl CreateLiNode(ITreeViewDataItem tvItem, int itemIndex, int itemLevelIndex, ref long uniqueKey) {
			var itemWrapper = new DataSourceWrapper.DataItemWraper(tvItem.DataItem);
			string key = tvItem.Key;
			var li = new TreeViewItemNode(key, ExpendedLevel + 1);
			if (tvItem.State == DataItemState.OnClientRequest) {
				li.TreeViewTitle.CreateCollapse(ClientName);
			} else if (tvItem.State == DataItemState.NoChild) {
				li.TreeViewTitle.CreateNoImage(ClientName);
			} else if (tvItem.State == DataItemState.BindingWithParrent) {
				li.TreeViewTitle.CreateExpend(ClientName);
			}

			var spText = li.TreeViewTitle.SpanContent;
			//	var item = new SpTreeNodeItemTemplate();
			spText.DataItem = itemWrapper.OriginalItem;
			spText.DataItemIndex = itemIndex;
			spText.DisplayIndex = itemIndex;
			uniqueKey++;

			if (ItemTemplate == null) {
				if (!String.IsNullOrEmpty(TextField))
					spText.InnerHtml = String.Format("{0}", itemWrapper.GetPropertyValue(TextField));
			} else {
				ItemTemplate.InstantiateIn(spText);
			}

			var itemBoundEventArgs = new SimpleItemBoundEventArgs<SpTreeNodeItemTemplate>(itemWrapper, spText);
			
			OnItemBound(itemBoundEventArgs);

			if (tvItem.State == DataItemState.BindingWithParrent && tvItem.Child != null) {
				HtmlGenericControl ulChild = new TreeViewRootNode();
				li.Controls.Add(ulChild);

				int childIndex = -1;
				foreach (var child in tvItem.Child) {
					childIndex++;
					HtmlGenericControl childLi = CreateLiNode(child, childIndex, itemLevelIndex + 1, ref uniqueKey);
					ulChild.Controls.Add(childLi);
				}
				//for (int i = 0; i < tvItem.Child.Count; i++) {
				//  HtmlGenericControl childLi = CreateLiNode(tvItem.Child[i], i, itemLevelIndex + 1, ref uniqueKey);
				//  ulChild.Controls.Add(childLi);
				//}
			}

			return li;
		}

		protected override void CreateClientObjectAtRender(HtmlTextWriter writer) {
			BeginScriptTag(writer);
			writer.Write(String.Format("var {0} = new SpTreeView();", ClientName));
			writer.Write(String.Format("{0}.Init('{0}', '{1}', '{2}', {3}, {4}, {5});",
																 ClientName,
																 _ul.ClientID,
																 (Int32)DisplayEffect,
																 TimeEffect,
																 StepEffect, AlwaysCallbackInExpend.ToString().ToLower()));

			AddScriptHandler(writer, 1, ClientScript.BeforeExpended, "AddHandler");
			AddScriptHandler(writer, 2, ClientScript.BeforeCallback, "AddHandler");
		
			EndScriptTag(writer);
		}

		protected override void Render(HtmlTextWriter writer) {

			if (Visible) {
				if (IsCallback) {
					WriteCustomCallbackCompleteResult();
					switch (RequestType) {
						case RequestType.Expended:
							_ul.Style.Remove(HtmlTextWriterStyle.Width);
							_ul.ID = String.Empty;
							_ul.RenderControl(writer);
							break;
						case RequestType.CustomCallback:
							foreach (Control c in _ul.Controls) {
								c.RenderControl(writer);
							}
							break;
						case RequestType.DataCallback:
							break;
					}

					FlushAndEndCallback();
				} else {
					_ul.Attributes.Add("root", "true");
					//_ul.Style["float"] = "left";
					_ul.Style["width"] = "100%";
					writer.RenderBeginTag(HtmlTextWriterTag.Div);

					base.Render(writer);
					writer.RenderEndTag();
				}
			}
		}
	}
}